package spring_learn.a16;

import org.springframework.aop.aspectj.AspectJExpressionPointcut;
import org.springframework.aop.support.StaticMethodMatcher;
import org.springframework.core.annotation.MergedAnnotations;
import org.springframework.transaction.annotation.Transactional;

import java.lang.reflect.Method;


/*
 a. 底层切点实现是如何匹配的: 调用了 aspectj 的匹配方法
 b. 比较关键的是它实现了 MethodMatcher 接口, 用来执行方法的匹配
 */
public class A16 {

    public static void main(String[] args) throws NoSuchMethodException {
        AspectJExpressionPointcut aspectJExpressionPointcut=new AspectJExpressionPointcut();
        aspectJExpressionPointcut.setExpression("execution(* f1())");
        //底层调用了AspectJExpressionPointcut的matches方法，判断一个对象的方法是否匹配对应的切点
        System.out.println(aspectJExpressionPointcut.matches(T1.class.getMethod("f1"),T1.class));
        System.out.println(aspectJExpressionPointcut.matches(T1.class.getMethod("f2"),T1.class));

        AspectJExpressionPointcut pt2=new AspectJExpressionPointcut();
        //对注解进行匹配
        pt2.setExpression("@annotation(org.springframework.transaction.annotation.Transactional)");
        //这里体现了AspectJExpressionPointcut的局限性
        //就是：只可以匹配直接的加在方法上的注解，但是如果类上加了注解/实现的接口上加了注解，是不可以匹配到的
        System.out.println(pt2.matches(T1.class.getMethod("f1"),T1.class));//true
        System.out.println(pt2.matches(T1.class.getMethod("f2"),T1.class));//false
        System.out.println(pt2.matches(T2.class.getMethod("f1"),T2.class));//false
        System.out.println(pt2.matches(T3.class.getMethod("f1"),T3.class));//false

        //解决办法 MethodMatcher接口
        //模拟
        StaticMethodMatcher methodMatcher=new StaticMethodMatcher() {
            @Override
            public boolean matches(Method method, Class<?> targetClass) {
                // 检查方法上是否加了 Transactional 注解
                MergedAnnotations annotations = MergedAnnotations.from(method);
                if (annotations.isPresent(Transactional.class)) {
                    return true;
                }
                // 查看类上是否加了 Transactional 注解
                annotations = MergedAnnotations.from(targetClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY);
                if (annotations.isPresent(Transactional.class)) {
                    return true;
                }
                return false;

            }
        };
        System.out.println(">>>>>>>>>>>>>>>>");
        System.out.println(methodMatcher.matches(T1.class.getMethod("f1"),T1.class));//true
        System.out.println(methodMatcher.matches(T1.class.getMethod("f2"),T1.class));//false
        System.out.println(methodMatcher.matches(T2.class.getMethod("f1"),T2.class));//false
        System.out.println(methodMatcher.matches(T3.class.getMethod("f1"),T3.class));//false

    }


    static class T1{

        @Transactional
        public void f1(){};

        public void f2(){};
    }

    @Transactional
    static class T2{
        public void f1(){};
    }

    @Transactional
    interface I3 {
        void f1();
    }
    static class T3 implements I3 {
        public void f1() {
        }
    }
}
